import logging
import os
import subprocess
import time
from datetime import datetime
from pathlib import Path

import uiautomation as auto
from pyzipper import AESZipFile

# 設置全局搜索超時時長
# auto.uiautomation.SetGlobalSearchTimeout(30)
from index.utils.log import Log

logger = Log(os.path.join(Path(__file__).parent.parent.parent, "logs"))


def create_directory(directory):
    """
    文件夾不存在時，創建文件夾
    :param directory:
    :return:
    """
    if not os.path.exists(directory):
        logger.info("創建文件夾用來保存附件")
        os.makedirs(directory)
    else:
        logger.info("删除原来的文件")
        for file in os.listdir(directory):
            os.remove(os.path.join(directory, file))


class SuperNotes(object):
    """
    本程序中使用的控件標識符，都是通過項目目錄下的 UISpay.exe 程序獲取
    參考文章： https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/blob/master/readme_cn.md
    """

    def __init__(self):
        # 定義打開郵件失敗重試次數
        self.open_retry_times = 3
        # 設置查詢郵件數量,由於前兩個不是郵件，所有需要設置數量加二
        self.find_mail_num = 12
        # 郵件路勁
        self.path = r'C:\Program Files (x86)\Super Notes\SuperNotes.exe'
        # 文件保存路徑
        self.save_path = os.path.join(Path(__file__).parent.parent, "files")
        create_directory(self.save_path)
        # 压缩档解压密码
        self.zip_password = "123"
        # 想要查询的归档
        self.directory = "門崗進出記錄"
        # 想要打開郵件的主旨
        self.target_mail = '門崗進出記錄'
        # 登錄信息
        self.user_name = 'idpbg-rf-wccc-common@mail.foxconn.com'
        self.password = 'RFsw123.'
        self.window = None

        # 打開郵件並登錄
        self.__open_and_login()

    def __open_and_login(self):
        """
        此方法用於打開郵件並執行登錄操作，可重複執行
        :return:
        """
        # 調用方法打開應用並獲取窗口
        self.window = self.__open_app()
        # 打開失敗不再繼續往後執行
        if self.window is None:
            logger.error('打開郵件獲取窗口失敗')
            return

        # 登錄
        self.__login()

    def __open_app(self):
        """
        用於打開郵件，如果打開失敗將重試3次
        :return:
        """
        try:
            logger.info("開始打開郵件。。。")
            if self.open_retry_times > 0:
                # 打開應用
                subprocess.Popen(self.path)
                time.sleep(2)
                # 窗口捕获
                window = auto.WindowControl(AutomationId="Main")
                # 設置窗口最大化
                window.Maximize()
                # 窗口置顶
                # window.SetTopmost()
                time.sleep(5)
                logger.info("打開郵件完成。。。")
                return window
            else:
                return None
        except Exception as e:
            logger.error(f"出現錯誤：{e}, 還有 {self.open_retry_times} 次重試機會")
            # 重試次數減一
            self.open_retry_times -= 1
            # 回調自身
            self.__open_app()

    def __login(self):
        """
        郵件登錄，判斷登錄情況
        1. 未登錄時： 執行登錄操作
        2. 登錄時：
         * 和當前用戶是同一個時： 不進行操作，直接跳過登錄方法
         * 和當前用戶不一致時： 關閉郵件，並調用 open_and_login 方法，重新執行一次打開登錄操作
        :return:
        """
        logger.info("開始進行登錄。。。")
        # 獲取標籤欄信息
        title = self.window.Name

        # 判斷是否需要登錄
        if 'foxconn.com' not in title.split(' ')[-1]:
            # 說明當前未登錄，需要登錄操作
            # 輸入賬號密碼
            self.window.ComboBoxControl(AutomationId='cbUserName').SendKeys(self.user_name)
            self.window.EditControl(AutomationId='tbPassword').SendKeys(self.password)
            # 點擊登錄
            self.window.ButtonControl(AutomationId='btnSure').Click()
            time.sleep(10)
            # 判斷是否登錄成功
            try:
                # 如果获取到了登录失败信息
                login_info = auto.TextControl(AutomationId='65535').Name
                logger.error(login_info)
                # 后续不在执行
                return
            except Exception as e:
                logger.info("登錄成功")
            # 插入一個回車鍵，跳過登錄之後的彈窗
            auto.PressKey(auto.Keys.VK_RETURN)
            time.sleep(5)
        else:
            # 此時郵件處於當前登錄者登錄狀態，無需再次登錄
            if self.user_name == title.split(' ')[-1]:
                logger.info("用戶已經登錄，跳過登錄過程")
                pass
            # 此時登錄了其他用戶賬號，需要重新登錄
            else:
                logger.info("不是當前用戶，重新打開郵件進行登錄")
                # 關閉郵件
                time.sleep(2)
                self.window.ButtonControl(Name='關閉').Click()
                time.sleep(2)
                # 調用 open_and_login
                logger.info("再次打開郵件，將 open_retry_times 重置為 3")
                self.open_retry_times = 3
                self.__open_and_login()

    def click_item(self):
        """
        點擊郵件，默認從前十條郵件中找目標郵件
        :return:
        """
        today_str = datetime.today().strftime('%Y/%m')
        logger.info(f'当前月份是 {today_str}')
        # 选择侧边栏
        tree_items = self.window.TreeControl(AutomationId='treeView1').GetChildren()
        for item in tree_items:
            # 找到对应的侧边栏, 进行点击
            if self.directory in item.Name:
                item.Click()
        time.sleep(2)

        # 所有郵件列表
        all_items = self.window.TableControl(AutomationId='dataGridView1').GetChildren()
        logger.info(f"從前 {self.find_mail_num - 2} 封郵件中尋找主旨包含 {self.target_mail} 的郵件")
        skip_num = 1
        if all_items[0].Name == '垂直捲軸':
            skip_num = 2
        for index, mail in enumerate(all_items):
            # 跳過前面兩個非郵件內容
            if index < skip_num:
                continue
            elif index == self.find_mail_num:
                # 到指定查詢郵件數量之後，結束循環,並關閉 SuperNotes
                self.window.ButtonControl(Name='關閉').Click()
                logger.info("執行完成, 未找到邮件, 關閉 SuperNotes")
                break

            # 查看主旨判斷是否是需要的郵件
            mail_title = mail.GetLastChildControl().GetValuePattern().Value
            # 邮件日期
            mail_date = mail.GetChildren()[10].GetValuePattern().Value
            if self.target_mail in mail_title and today_str in mail_date:
                logger.info(f"正在打開第 {index - 1} 封郵件，主旨為： {mail_title}")
                mail.DoubleClick()

                # 下載附件
                time.sleep(2)
                self.__download_file()
                time.sleep(2)

                # 切換到信箱tab
                self.window.TabControl(AutomationId='tabControl1').TabItemControl(Name='信箱').Click()
                time.sleep(2)

                self.window.ButtonControl(Name='關閉').Click()
                logger.info(f"完成下载, 关闭 SuperNotes")
                break
            else:
                logger.info(f"第 {index - 1} 封郵件主旨為 {mail_title}，但不是目標郵件，跳過")

    def __download_file(self):
        """
        下載附件的文件到指定目錄
        :return:
        """
        file_control = self.window.ListControl(AutomationId='listView1').GetChildren()[0]
        if file_control.Exists():
            # 右键文件進行下載
            file_control.RightClick()
            # 點擊內存為
            self.window.MenuControl(Name='DropDown').GetChildren()[1].Click()
            time.sleep(1)
            # 輸入保存路徑
            self.window.EditControl(Name='檔案名稱:').SendKeys(os.path.join(self.save_path, file_control.Name))
            time.sleep(1)
            # 點擊保存
            self.window.ButtonControl(Name="存檔(S)").Click()
            time.sleep(1)
            # 判斷文件衝突窗口是否存在
            conform_new = self.window.WindowControl(Name="確認另存新檔")
            if conform_new.Exists():
                logger.info("文件存在，將覆蓋原文件")
                conform_new.ButtonControl(Name="是(Y)").Click()
                time.sleep(1)
                # 還需要確認一個窗口
                self.window.WindowControl(Name='提示信息').ButtonControl(Name="是(Y)").Click()
                time.sleep(2)
            # 下載成功後關閉提示窗口
            self.window.WindowControl(AutomationId='FrmPlan').ButtonControl(Name='取消').Click()
            time.sleep(1)
            logger.info("文件下載完成")
            # 将压缩档加压
            if '.zip' in file_control.Name:
                try:
                    # 打开 ZIP 文件，输入密码
                    with AESZipFile(os.path.join(self.save_path, file_control.Name), 'r') as zip_ref:

                        zip_ref.extractall(pwd=self.zip_password.encode(), path=self.save_path)
                        # 将文件重命名
                        os.rename(os.path.join(self.save_path, zip_ref.namelist()[0]),
                                  os.path.join(self.save_path, '普通門崗刷卡明細查詢數據.xls'))

                except Exception as e:
                    print(f"发生错误: {e}")
                logger.info("解压文件")
            else:
                # 重命名文件
                os.rename(os.path.join(self.save_path, file_control.Name),
                          os.path.join(self.save_path, '普通門崗刷卡明細查詢數據.xls'))
        else:
            logger.error("沒有找到文件，無法執行下載")


if __name__ == '__main__':
    super_notes = SuperNotes()
    super_notes.click_item()





